package com.itaming.lycheeframework.support.utils;

import lombok.experimental.UtilityClass;
import org.springframework.core.DefaultParameterNameDiscoverer;
import org.springframework.core.MethodParameter;
import org.springframework.core.ParameterNameDiscoverer;
import org.springframework.core.annotation.AnnotatedElementUtils;
import org.springframework.core.annotation.SynthesizingMethodParameter;
import org.springframework.util.ClassUtils;
import org.springframework.web.method.HandlerMethod;

import java.lang.annotation.Annotation;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;

/**
 * Class工具类
 *
 * @author A.Ming
 */
@UtilityClass
public class ClassUtil extends ClassUtils {

    /**
     * 参数名解析器
     */
    private static final ParameterNameDiscoverer PARAMETER_NAME_DISCOVERER = new DefaultParameterNameDiscoverer();

    /**
     * 获取类型
     *
     * @param objects 对象
     * @return 类型数组
     */
    public static Class<?>[] getClasses(Object... objects) {
        Class<?>[] classes = new Class[objects.length];
        for (int i = 0; i < objects.length; i++) {
            if (objects[i] == null) {
                classes[i] = Object.class;
            } else {
                classes[i] = objects[i].getClass();
            }
        }
        return classes;
    }

    /**
     * 获取构造方法参数信息
     *
     * @param constructor    构造方法
     * @param parameterIndex 参数索引
     * @return 方法参数信息
     */
    public static MethodParameter getConstructorParameter(Constructor<?> constructor, int parameterIndex) {
        MethodParameter methodParameter = new SynthesizingMethodParameter(constructor, parameterIndex);
        methodParameter.initParameterNameDiscovery(PARAMETER_NAME_DISCOVERER);
        return methodParameter;
    }

    /**
     * 获取方法参数信息
     *
     * @param method         方法
     * @param parameterIndex 参数索引
     * @return 方法参数信息
     */
    public static MethodParameter getMethodParameter(Method method, int parameterIndex) {
        MethodParameter methodParameter = new SynthesizingMethodParameter(method, parameterIndex);
        methodParameter.initParameterNameDiscovery(PARAMETER_NAME_DISCOVERER);
        return methodParameter;
    }

    /**
     * 获取注解
     *
     * @param method         方法
     * @param annotationType 注解类
     * @return 注解
     */
    public static <A extends Annotation> A getAnnotation(Method method, Class<A> annotationType) {
        // 获取方法上的注解
        A annotation = AnnotatedElementUtils.findMergedAnnotation(method, annotationType);
        if (null != annotation) {
            return annotation;
        }

        // 获取类上面的注解
        return AnnotatedElementUtils.findMergedAnnotation(method.getDeclaringClass(), annotationType);
    }

    /**
     * 获取注解
     *
     * @param handlerMethod  HandlerMethod
     * @param annotationType 注解类
     * @return 注解
     */
    public static <A extends Annotation> A getAnnotation(HandlerMethod handlerMethod, Class<A> annotationType) {
        // 获取方法上的注解
        A annotation = handlerMethod.getMethodAnnotation(annotationType);
        if (annotation != null) {
            return annotation;
        }

        // 获取类上面的注解
        Class<?> beanType = handlerMethod.getBeanType();
        return AnnotatedElementUtils.findMergedAnnotation(beanType, annotationType);
    }

    /**
     * 判断是否有指定的注解
     *
     * @param method         方法
     * @param annotationType 注解类
     * @return boolean
     */
    public static <A extends Annotation> boolean isAnnotated(Method method, Class<A> annotationType) {
        return getAnnotation(method, annotationType) != null;
    }

    /**
     * 判断是否有指定的注解
     *
     * @param handlerMethod  HandlerMethod
     * @param annotationType 注解类
     * @return boolean
     */
    public static <A extends Annotation> boolean isAnnotated(HandlerMethod handlerMethod, Class<A> annotationType) {
        return getAnnotation(handlerMethod, annotationType) != null;
    }

}
